package com.water.gateway.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.logout.ServerLogoutHandler;
import org.springframework.security.web.server.authentication.logout.ServerLogoutSuccessHandler;
import org.springframework.security.web.server.authentication.logout.WebSessionServerLogoutHandler;
import org.springframework.web.server.session.InMemoryWebSessionStore;

import reactor.core.publisher.Mono;

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
	@Autowired
	private ReactiveOAuth2AuthorizedClientService authorizedClientService;

	@Bean
	public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http,
			ReactiveClientRegistrationRepository clientRegistrationRepository) {
		http.csrf(csrf -> csrf.disable());
		http.authorizeExchange(exchanges -> exchanges.pathMatchers("/api/**").permitAll()
				.pathMatchers(HttpMethod.OPTIONS, "/**").permitAll()
				// .pathMatchers("/login", "/logout").permitAll()
				.anyExchange().authenticated());
		http.oauth2Login(Customizer.withDefaults()); // 开启OAuth2登录
		http.oauth2Client(Customizer.withDefaults());
		http.logout(logout -> logout.logoutUrl("/logout") // 触发注销的API路径
				.logoutHandler(serverLogoutHandler()) // 清理会话
				.logoutSuccessHandler(oidcLogoutSuccessHandler(clientRegistrationRepository)));
		// https://docs.spring.io/spring-security/reference/reactive/authentication/logout.html
		// DelegatingServerLogoutHandler logoutHandler = new DelegatingServerLogoutHandler(
		//         new SecurityContextServerLogoutHandler(), new WebSessionServerLogoutHandler()
		// );
		// http.logout((logout) -> logout.logoutHandler(logoutHandler));
		http.securityContextRepository(securityContextRepository());

		return http.build();
	}

	@Bean
	public CustomSecurityContextRepository securityContextRepository() {
		return new CustomSecurityContextRepository();
	}

	@Bean
	public InMemoryWebSessionStore sessionRepository() {
		return new InMemoryWebSessionStore();
	}

	public Mono<String> getAccessToken(OAuth2AuthenticationToken authentication) {
		return authorizedClientService
				.loadAuthorizedClient(authentication.getAuthorizedClientRegistrationId(), authentication.getName())
				.map(client -> client.getAccessToken().getTokenValue());
	}

	@Bean
	public GlobalFilter tokenRelayFilter() {
		return (exchange, chain) -> {
			return exchange.getPrincipal().doOnNext(principal -> System.out.println("-->Principal: " + principal))
					.cast(OAuth2AuthenticationToken.class).flatMap(auth -> {
						return chain.filter(exchange);
					});
		};
	}

	// @Bean
	public ServerLogoutHandler serverLogoutHandler() {
		new WebSessionServerLogoutHandler();
		// return new WebSessionServerLogoutHandler(); // 处理 WebFlux 会话清理
		return (exchange, authentication) -> {
			System.out.println("执行 LogoutHandler：清理认证信息");
			return exchange.getExchange().getSession().flatMap(session -> {
				System.out.println("--serverLogoutHandler--->");
				session.getAttributes().clear();
				session.invalidate();
				ReactiveSecurityContextHolder.clearContext(); // Clear authentication
				return Mono.empty();
			});
		};
	}

	// @Bean
	public ServerLogoutSuccessHandler oidcLogoutSuccessHandler(
			ReactiveClientRegistrationRepository clientRegistrationRepository) {
		// OidcClientInitiatedServerLogoutSuccessHandler handler = new OidcClientInitiatedServerLogoutSuccessHandler(clientRegistrationRepository);
		CustomServerLogoutSuccessHandler handler = new CustomServerLogoutSuccessHandler(clientRegistrationRepository);
		return handler;
	}
}
